home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Patterns / DocView.m < prev    next >
Text File  |  1992-12-19  |  9KB  |  366 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    DocView.m
  35.  *
  36.  *    This class handles the scaling of the drawing view. It repositions
  37.  *    The drawing view within itself if the drawing view is smaller than the
  38.  *    size of the clip view. The size of the doc view is:
  39.  *    MAX(clip view frame, drawing view frame).
  40.  *
  41.  *    Version:    2.0
  42.  *    Author:    Ken Fromm
  43.  *    History:
  44.  *            03-07-91        Added this comment.
  45.  */
  46.  
  47. #import "DocView.h"
  48.  
  49. #import <appkit/NXCursor.h>
  50. #import <appkit/NXImage.h>
  51. #import <appkit/Matrix.h>
  52. #import <appkit/ScrollView.h>
  53. #import <dpsclient/wraps.h>
  54. #import <appkit/nextstd.h>
  55.  
  56. @implementation DocView
  57.  
  58. /*
  59. *    Since there is only one subview its easier to keep track of it as an
  60. *    instance variable rather than in the subview list.  Returns any the
  61. *    previous drawing view.
  62. */
  63. - setDrawView:aView
  64. {
  65.     id        oldView;
  66.  
  67.     oldView = drawviewId;
  68.     [oldView  removeFromSuperview];
  69.  
  70.     [self  addSubview:aView];
  71.     drawviewId = aView;
  72.     
  73.     return oldView;
  74. }
  75.  
  76. - drawView
  77. {
  78.     return drawviewId;
  79. }
  80.  
  81. - setZoomControl:anObject
  82. {
  83.     zoomControl = anObject;
  84.     
  85.     return self;
  86. }
  87.  
  88. - zoomControl
  89. {
  90.     return zoomControl;
  91. }
  92.  
  93. - setHitSetting:(float) value
  94. {    
  95.     hitsetting = value;
  96.  
  97.     return self;    
  98. }
  99.  
  100. /*
  101. *    Scale the hit setting. Using an unscaled hit setting would be like
  102. *    using a boxing glove on a 400% scale.
  103. */
  104. - (float) hitSetting
  105. {    
  106.     return hitsetting * (1.0/scale);
  107. }
  108.  
  109. - setScale:(float)value
  110. {
  111.     scale = value;
  112.     
  113.     return self;
  114. }
  115.  
  116. - (float) scale
  117. {
  118.     return  scale;
  119. }
  120.  
  121. - setZooming:(BOOL)flag
  122. {
  123.     zooming = flag;
  124.     
  125.     return self;
  126. }
  127.  
  128. - (BOOL) isZooming
  129. {
  130.     return zooming;
  131. }
  132.  
  133. /*
  134. *    This method is overridden from the View class. When the
  135. *    user is zooming the cursor rect for the zoom cursor is set
  136. *    the the frame of the drawing view.
  137. */
  138. - resetCursorRects
  139. {
  140.     NXPoint        hotspot;
  141.  
  142.     NXRect        cursorRect, visRect;
  143.  
  144.     if (zooming)
  145.     {
  146.         if (!zoomCursor)
  147.         {
  148.             hotspot.x = hotspot.y = 8.0;
  149.             zoomCursor = [NXCursor  newFromImage:[NXImage  newFromSection:"zoom.tiff"]];
  150.             [zoomCursor setHotSpot:&hotspot];
  151.         }
  152.  
  153.         [self  getVisibleRect:&visRect];
  154.         [drawviewId getFrame:&cursorRect];
  155.         NXIntersectionRect(&visRect, &cursorRect);
  156.         [self addCursorRect:&cursorRect  cursor:zoomCursor];
  157.     }
  158.  
  159.     return self;
  160. }
  161.  
  162. /*
  163. *    Messaged from the zoom matrix. Starts the zoom loop. At the next
  164. *    mouse down in the drawing view, the scaleDrawView:toPoint: method
  165. *    will be called.
  166. */
  167. - zoom:sender
  168. {
  169.     [self  setZooming:YES];
  170.     [self  setZoomControl:sender];
  171.     [self  resetCursorRects];
  172.  
  173.     [window makeKeyAndOrderFront:self];
  174.  
  175.     return self;
  176. }
  177.  
  178. /*
  179. *    Sizes the drawing view from the old scale to the newscale.
  180. *    The frame of the view is used instead of the bounds because
  181. *    the bound will always be the same whereas the frame will
  182. *    provide the size in default coordinates.
  183. */
  184. - sizeDrawViewWithScale:(float) newscale
  185. {
  186.     float            scalefactor, sizewidth, sizeheight;
  187.  
  188.     NXRect        viewFrame;
  189.     
  190.     [drawviewId  getFrame:&viewFrame];
  191.     scalefactor = newscale/scale;
  192.     sizewidth = viewFrame.size.width*scalefactor;
  193.     sizeheight = viewFrame.size.height*scalefactor;
  194.     [drawviewId  sizeTo:rint(sizewidth) :rint(sizeheight)];
  195.  
  196.     return self;
  197. }
  198.  
  199. /* 
  200. *    Scales the drawing view from the old scale to the new scale.
  201. *    The scale method is relative so we use the ratio
  202. *    of the old scale to the new scale to obtain the scaling factor.
  203. */
  204. - scaleDrawViewWithScale:(float) newscale
  205. {
  206.     float     scalefactor;
  207.  
  208.     scalefactor = newscale/scale;
  209.     [drawviewId  scale:scalefactor  :scalefactor];
  210.  
  211.     return self;
  212. }
  213.  
  214. /*
  215. *    Place the view passed in in the center of the doc view
  216. *    if it is smaller than the size of the ClipView. Two passes are made
  217. *    through the loop because adding or removing a horizontal or
  218. *    vertical scrollbar will affect the size of the remaining dimension .
  219. */
  220. - placeDrawView
  221. {
  222.     float            margin;
  223.     
  224.     NXSize        contSize, newSize, insetSize, delta;
  225.  
  226.     NXRect         viewFrame;
  227.  
  228.     margin = 4 * OFFSET * scale;
  229.     [drawviewId  getFrame:&viewFrame];
  230.     [[superview  superview]  getContentSize:&contSize];
  231.  
  232.     newSize.width = MAX(viewFrame.size.width, contSize.width);
  233.     newSize.height = MAX(viewFrame.size.height, contSize.height);
  234.  
  235.     delta.width = newSize.width - viewFrame.size.width;
  236.     delta.height = newSize.height - viewFrame.size.height;
  237.     if (delta.width != 0.0 || delta.height != 0.0)
  238.     {
  239.         if (delta.width < margin)
  240.             newSize.width += margin - delta.width;
  241.         if (delta.height < margin)
  242.             newSize.height += margin - delta.height;
  243.     }
  244.     
  245.     [self  sizeTo:newSize.width  :newSize.height];
  246.  
  247.     insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
  248.     insetSize.height =  floor((newSize.height - viewFrame.size.height)/2);
  249.     [drawviewId  moveTo:insetSize.width  :insetSize.height];
  250.     if (insetSize.width != 0 || insetSize.height != 0)
  251.         [drawviewId  setClipping:YES];
  252.     else
  253.         [drawviewId setClipping:NO];
  254.  
  255.     return self;
  256. }
  257.  
  258. /*
  259. *    Scales the view to the tag of the selected matrix cell and then
  260. *    scrolls to the point. The point is in window coordinates so
  261. *    it must be converted to the drawing view  coordinates in order
  262. *    to position it in the same relative place in the view.
  263. */
  264. - scaleDrawViewToPoint:(NXPoint *) p;
  265. {
  266.     float            newscale;
  267.  
  268.     NXPoint        viewPt;
  269.  
  270.     [window invalidateCursorRectsForView:self];
  271.     newscale = [zoomControl  selectedTag] * 0.01;
  272.     if (drawviewId && newscale != scale)
  273.     {
  274.         viewPt = *p;
  275.         [drawviewId  convertPoint:&viewPt  fromView:nil];
  276.         [window disableDisplay];
  277.             /* Size and then scale the drawing view. The frame of the */
  278.             /* drawing view must reflect the changed size. Scaling */
  279.             /* alone will not change the frame. */
  280.             [self  sizeDrawViewWithScale:newscale];
  281.             [self  scaleDrawViewWithScale:newscale];
  282.             [self  setScale:newscale];
  283.     
  284.             [self  placeDrawView];
  285.             [self  scrollDrawPoint:&viewPt  toWindowPoint:p];
  286.         [window reenableDisplay];
  287.         [[window contentView]  display];
  288.     }
  289.     [self  setZooming:NO];
  290.  
  291.     return self;
  292. }
  293.  
  294. /*
  295.  *    Use the point location relative to the window versus the point relative
  296.  *    to the drawing view (before the scale) to determine where to scroll
  297.  *    the drawing view. We want the same location in the drawing view to
  298.  *    appear where the mouse downed occurred.  The window coordinates
  299.  *    are used and then adjusted by the position of the scrolling frame
  300.  *    because the presence or absence of scrollbars throws the use
  301.  *    of the doc views coordinates awry.
  302.  */    
  303. - scrollDrawPoint:(const NXPoint *) aPt  toWindowPoint:(const NXPoint *) windowPt
  304. {
  305.     NXPoint        viewPt, scrollPt;
  306.  
  307.     NXRect         clipFrame, visRect;
  308.  
  309.     [superview  getFrame:&clipFrame];
  310.     if (frame.size.width > clipFrame.size.width || frame.size.height > clipFrame.size.height)
  311.     {
  312.         viewPt = *aPt;
  313.         [drawviewId  convertPointToSuperview:&viewPt];
  314.  
  315.         scrollPt = *windowPt;
  316.         [self  convertPoint:&scrollPt  fromView:nil];
  317.         [self  getVisibleRect:&visRect];
  318.         viewPt.x  -= (scrollPt.x - visRect.origin.x);
  319.         viewPt.y  -= (scrollPt.y - visRect.origin.y);
  320.         [self  scrollPoint:&viewPt];        
  321.     }
  322.  
  323.     return self;
  324. }
  325.  
  326. /*
  327.  * This drawSelf method draws a border around the drawing view as well as a
  328.  * drop shadow.  This is only done if it will be visible however. We tell if it is visible
  329.  * if the rectangle passed in is not contained entirely within drawingView frame.
  330. */
  331. - drawSelf:(NXRect *)r :(int) count
  332. {
  333.     NXRect        drawRect, dropRect, bRect, xRect, yRect;
  334.  
  335.     /* Calculate the rectangle of the draw view plus its drop shadow. */
  336.     [drawviewId  getFrame:&drawRect];
  337.     dropRect = bRect = drawRect;
  338.     NXOffsetRect(&bRect, -rint(LINEWIDTH/2 * scale), -rint(LINEWIDTH/2 * scale));
  339.     NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  340.     NXUnionRect(&dropRect, &bRect);
  341.     if (!NXContainsRect(&bRect, r))
  342.     {
  343.         bRect = xRect = yRect = dropRect;
  344.         NXIntersectionRect(&drawRect, &bRect);
  345.         NXDivideRect(&xRect, &dropRect, bRect.size.width, 0);
  346.         NXDivideRect(&yRect, &dropRect, bRect.size.height, 3);
  347.  
  348.         PSgsave();
  349.             PSsetgray(NX_BLACK);
  350.             PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
  351.             PSrectfill(xRect.origin.x, xRect.origin.y,
  352.                 xRect.size.width, xRect.size.height);
  353.             PSrectfill(yRect.origin.x, yRect.origin.y,
  354.                 yRect.size.width, yRect.size.height);
  355.             PSsetlinewidth(LINEWIDTH * scale);
  356.             PSrectstroke(drawRect.origin.x, drawRect.origin.y,
  357.                 drawRect.size.width, drawRect.size.height);
  358.         PSgrestore();
  359.     }
  360.  
  361.     return self;            
  362. }
  363.  
  364. @end
  365.  
  366.